package com.example.spring_gobang.game;

import com.example.spring_gobang.messgae.MatchResponse;
import com.example.spring_gobang.model.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

//这个类表示匹配器
//通过这个类完成匹配
//设置三个等级匹配 因此需要创建三个匹配队列
@Component
public class Matcher {
    private Queue<UserInfo> low = new LinkedList<>();
    private Queue<UserInfo> medium = new LinkedList<>();
    private Queue<UserInfo> hight = new LinkedList<>();
    @Autowired
    private OnlineUserManage manage;
    @Resource
    private ObjectMapper objectMapper;

    @Autowired
    private RoomManager roomManager;
    //加入匹配队列
    public void add(UserInfo userInfo){
        if (userInfo.getScore() < 2000){
            synchronized (low) {
                low.offer(userInfo);
                System.out.println("玩家" + userInfo.getUsername() + "加入到low匹配队列中");
                low.notify();
            }
        }else if (userInfo.getScore() >= 2000 && userInfo.getScore() < 3000 ){
            synchronized (medium) {
                medium.offer(userInfo);
                medium.notify();
            }
        }else {
            synchronized (hight) {
                hight.offer(userInfo);
                hight.notify();
            }
        }
    }
    //当玩家点击取消匹配的时候 就从匹配队列中把该玩家删除
    public void remove(UserInfo userInfo){
        //使用while 队列的初始情况可能为空
        if (userInfo.getScore() < 2000){
            synchronized (low) {
                low.remove(userInfo);
            }
        }else if (userInfo.getScore() >= 2000 && userInfo.getScore() < 3000){
            synchronized (medium) {
                medium.remove(userInfo);
            }
        }else {
            synchronized (hight) {
                hight.remove(userInfo);
            }
        }
    }
    public Matcher(){
        //创建三个扫描线程用来扫描三个队列
        Thread t1 = new Thread(() ->{
           while (true){
               handleMatch(low);
           }
        });
        t1.start();
        Thread t2 = new Thread(() ->{
            while (true){
                handleMatch(medium);
            }
        });
        t2.start();
        Thread t3 = new Thread(() ->{
           while (true){
               handleMatch(hight);
           }
        });
        t3.start();
    }

    private void handleMatch(Queue<UserInfo> matchQueue)  {
        //直接针对形参进行加锁 这样相当于针对三个匹配队列进行加锁
        synchronized (matchQueue) {
            try {
                //使用while 防止队列为空的情况 出现只有一个玩家的情况
                while (matchQueue.size() < 2){
                    matchQueue.wait();
                }
                //从匹配队列中取出两个玩家
                UserInfo userInfo1 = matchQueue.poll();
                UserInfo userInfo2 = matchQueue.poll();
                System.out.println("从匹配队列中取出两个玩家" + userInfo1.getUsername() + userInfo2.getUsername());
                WebSocketSession session1 = manage.getFromById(userInfo1.getUserId());
                WebSocketSession session2 = manage.getFromById(userInfo2.getUserId());
                //TODO 使用双重校验会更加稳妥
                //如果玩家1不在线了
                if (session1 == null){
                    matchQueue.offer(userInfo2);
                    return;
                }
                //如果玩家2不在线了
                if (session2 == null){
                    matchQueue.offer(userInfo1);
                    return;
                }
                if (session1 == session2){
                    //两个取出的玩家一样 随便找一个放入匹配队列中去
                    matchQueue.offer(userInfo1);
                }
                //TODO 把这两个玩家放入到一个游戏房间中去。
                Room room = new Room();
                roomManager.add(room,userInfo1.getUserId(),userInfo2.getUserId());
                //TODO 通过websocket给玩家发送消息 你匹配到对手了
                //通过webSocket发一个与前端约定好的matchSuccess消息
                //给玩家1推送消息
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response1)));
                //给玩家2推送消息
                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
